home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gekkan Dennou Club 147
/
Gekkan Dennou Club - 2000.8 Vol. 147 (Japan).7z
/
Gekkan Dennou Club - 2000.8 Vol. 147 (Japan) (Track 1).bin
/
docs
/
complex
/
julia3.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-06-21
|
6KB
|
254 lines
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <iocslib.h>
#include <doslib.h>
#include <math.h>
#include <time.h>
#include "complex.h"
#define USAGE "\
3次方程式のジュリア集合を描く\n\
使用法: julia3 [reMin imMax scLen [scSize [mxCnt [rot_f_limit [Re_A Im_A [Re_B Im_B [Re_C Im_C]]]]]]]\n\
Newton法の初期値について reMin=実部最小[-2.0], imMax=虚部最大[2.0], scLen=辺の長さ[4.0]\n\
scSize=画面サイズ(0…256×256ドット, 1…512×512ドット)[0]\n\
mxCnt=回数制限(1~65535)[256]\n\
rot_f_limit=収束半径(収束したと判断する|f(z)|の上限)[0.01]\n\
Re_A=2次の係数の実部[0.0], Im_A=2次の係数の虚部[0.0]\n\
Re_B=1次の係数の実部[0.0], Im_B=1次の係数の虚部[0.0]\n\
Re_C=定数項の実部[-1.0], Im_C=定数項の虚部[0.0]\n\
f(z)=z^3+A*z^2+B*z+C\n\
"
/* 画面サイズのデフォルト */
#define SC_SIZE 0
/* 計算範囲のデフォルト */
#define RE_MIN (-2.0)
#define IM_MAX (2.0)
#define SC_LEN (4.0)
/* 最大ループ回数のデフォルト */
#define MX_CNT 256
/* 収束判定の制度 */
#define ROT_F_LIMIT (0.01)
/* キーチェック */
#define keysns() \
({ \
int _k_ = 0; \
while (B_KEYSNS()) _k_ = B_KEYINP() & 0xff ? : _k_; \
_k_; \
})
double reMin = RE_MIN, imMax= IM_MAX;
double scLen = SC_LEN;
int scSize = SC_SIZE;
int mxCnt = MX_CNT;
double rot_f_limit = ROT_F_LIMIT;
double rot_f_limit2;
unsigned short *paTable; /* パレットテーブル */
void make_palet_table(void); /* パレットテーブルを作る */
void init_screen(void); /* 画面の初期化 */
void tini_screen(void); /* 画面の後始末 */
/* 係数と定数項のデフォルト */
#define Re_A (0.0)
#define Im_A (0.0)
#define Re_B (0.0)
#define Im_B (0.0)
#define Re_C (-1.0)
#define Im_C (0.0)
/* 係数と定数項 */
complex A, B, C;
/* f(z),df_f(z)を変更することで別のジュリア集合を描くことができる */
/* f(z)=z^3+A*z^2+B*z+C, df_f(z)=3*z^2+2*A*z+B */
/* マクロ版と関数版のどちらか速い方を選択する */
#if 0
#define f(z) cadd(cadd(cadd(cpow3(z), cmul(cpow2(z), A)), cmul((z), B)), C)
#define df_f(z) cadd(cadd(cremul(cpow2(z), 3.0), cremul(cmul((z), A), 2.0)), B)
#else
complex f(complex z)
{
return cadd(cadd(cadd(cpow3(z), cmul(cpow2(z), A)), cmul(z, B)), C);
}
complex df_f(complex z)
{
return cadd(cadd(cremul(cpow2(z), 3.0), cremul(cmul(z, A), 2.0)), B);
}
#endif
/* 初期値cでf(z)に対するNewton法の漸化式の反復回数を返す */
int iteration(complex c, int limit_cnt)
{
complex z;
int cnt;
if (setjmp(cjmpenv)) {
return limit_cnt; /* 計算できなかった */
}
cnt = limit_cnt;
z = c;
while (cnt > 0 && cabs2(f(z)) > rot_f_limit2) {
/* f(z)に対するNewton法の漸化式 rec_f(z)=z-f(z)/df_f(z) */
z = csub(z, cdiv(f(z), df_f(z)));
cnt--;
}
return limit_cnt - cnt;
}
/* 描画ルーチンの本体 */
void draw_body()
{
unsigned short *a;
complex c;
double step;
unsigned short scCnt;
unsigned short reCnt;
unsigned short imCnt;
complex c0;
scCnt = (scSize ? 512 : 256);
step = scLen / (double)scCnt;
/* VRAMの書き込みアドレス */
a = (unsigned short *)0xc00000;
c0 = tocomplex(reMin, imMax);
/* 虚軸方向のループ */
for (imCnt = 0; imCnt < scCnt; imCnt++) {
{
unsigned short *b;
b = a;
/* これから描画するラスタを示すための点線を描く */
for (reCnt = 0; reCnt < 512; reCnt += 8) {
*b = 0xffff;
b += 8;
}
}
c = c0;
/* 解像度に応じて実軸方向のループ全体を分ける */
if (scSize == 0) {
/* 256×256ドット */
/* 実軸方向のループ */
for (reCnt = 0; reCnt < scCnt; reCnt++) {
unsigned short col;
/* 漸化式の反復回数を数えてパレットテーブルを参照する */
col = paTable[iteration(c, mxCnt)];
/* 解像度に応じた大きさの点をVRAMに書き込む */
*a++ = col;
*a++ = col;
a[512-2] = col;
a[512-1] = col;
/* 実軸方向に進む */
Re(c) += step;
}
} else {
/* 512×512ドット */
/* 実軸方向のループ */
for (reCnt = 0; reCnt < scCnt; reCnt++) {
/* 漸化式の反復回数を数えてパレットテーブルを参照する */
/* 解像度に応じた大きさの点をVRAMに書き込む */
*a++ = paTable[iteration(c, mxCnt)];
/* 実軸方向に進む */
Re(c) += step;
}
}
/* 解像度に応じてVRAMの書き込みアドレスを補正する */
if (scSize == 0) {
a += 512;
}
/* 虚軸方向に進む */
Im(c0) -= step;
/* キーが押されたら中止 */
if (keysns()) {
break;
}
}
}
void main(int argc, char *argv[])
{
clock_t tm0, tm1;
/* 画面の初期化 */
init_screen();
/* 係数と定数項のデフォルトを設定 */
A = tocomplex(Re_A, Im_A);
B = tocomplex(Re_B, Im_B);
C = tocomplex(Re_C, Im_C);
/* コマンドラインのパラメータを取得 */
switch (argc) {
case 13:
sscanf(argv[12], "%lf", &Im(C));
sscanf(argv[11], "%lf", &Re(C));
case 11:
sscanf(argv[10], "%lf", &Im(B));
sscanf(argv[9], "%lf", &Re(B));
case 9:
sscanf(argv[8], "%lf", &Im(A));
sscanf(argv[7], "%lf", &Re(A));
case 7:
sscanf(argv[6], "%lf", &rot_f_limit);
case 6:
sscanf(argv[5], "%d", &mxCnt);
case 5:
sscanf(argv[4], "%d", &scSize);
case 4:
sscanf(argv[3], "%lf", &scLen);
sscanf(argv[2], "%lf", &imMax);
sscanf(argv[1], "%lf", &reMin);
case 1:
break;
default:
printf(USAGE);
return;
}
/* 収束半径を2乗しておく */
rot_f_limit2 = rot_f_limit * rot_f_limit;
/* パレットテーブルを作る */
make_palet_table();
/* VRAMに直接書き込むためにスーパーバイザモードにする */
B_SUPER(0);
/* 計測開始 */
{
clock_t t = clock();
while ((tm0 = clock()) == t);
}
/* 描画ルーチンの本体 */
draw_body();
/* 計測終了 */
tm1 = clock();
/* 画面の後始末 */
tini_screen();
/* 所要時間を表示 */
printf("所要時間は %.8g 秒です.\n", ((double)(tm1 - tm0)) / CLK_TCK);
}